#include "PC.h"

int sc_main (int argc , char* argv[])
{
	sc_set_time_resolution(1, SC_PS);
	sc_set_default_time_unit(1, SC_PS);
	sc_set_stop_mode(SC_STOP_IMMEDIATE);

	sc_signal<bool> RSTn;
	sc_clock CPU_CLK("CPU_CLK", 1000000/CPU_FREQ, SC_PS);
	sc_clock DRAM_CLK("DRAM_CLK", 1000000/DRAM_FREQ, SC_PS);
	sc_clock PCIe_CLK("PCIe_CLK", 1000000/PCIe_FREQ, SC_PS);
	sc_clock SATA_CLK("SATA_CLK", 1000000/SATA_FREQ, SC_PS);
	sc_clock FLASH_CLK("FLASH_CLK", 1000000/FLASH_FREQ, SC_PS);
/*
	sc_buffer<byte>	DATA_IO;
	sc_signal<bool>	R_nB;
	sc_buffer<bool>	REb;
	sc_buffer<bool>	WEb;	
*/
	sc_signal<int> HTx_Dword;
	sc_signal<int> HRx_Dword;

	CPU*					CPU_1;
	PCIe_Root_Complex*		Root_Complex;
	PCIe_Switch*			Switch;
	PCIe_SATA_Controller*	SATA_Controller_1;
	SDRAM_DDR_device*		DDR_SDRAM_1;
	SDRAM_DDR_DP_device*	DPDRAM_1;
	DDR_SSD*				DDR_SSD_1;
	NAND_device*			DDR_SSD_NAND_1;
	NAND_device*			DDR_SSD_NAND_2;
	SATA_SSD*				SATA_SSD_1;
	NAND_device*			SATA_SSD_NAND_1;
	NAND_device*			SATA_SSD_NAND_2;
//	NAND_flash*				NAND_Flash;

	PCIe_address_space addr_DRAM_MEM_1(MEM,
									   0x0, DRAM_MEM_START_ADDRESS_UNDER_4G,
									   0x0, DRAM_MEM_END_ADDRESS_UNDER_4G);
	PCIe_address_space addr_DRAM_IO(IO,
									0x0, DRAM_IO_START_ADDRESS,
									0x0, DRAM_IO_END_ADDRESS);
	PCIe_address_space addr_DRAM_CONF(CONF,
									  0x0, DRAM_CONF_START_ADDRESS,
									  0x0, DRAM_CONF_END_ADDRESS);

	PCIe_address_space addr_DMI_MEM_1(MEM,
									  0x0, DMI_MEM_START_ADDRESS_UNDER_4G,
									  0x0, DMI_MEM_END_ADDRESS_UNDER_4G);
	PCIe_address_space addr_DMI_IO(IO,
								   0x0, DMI_IO_START_ADDRESS,
								   0x0, DMI_IO_END_ADDRESS);
	PCIe_address_space addr_DMI_CONF(CONF,
									 0x0, DMI_CONF_START_ADDRESS,
									 0x0, DMI_CONF_END_ADDRESS);

	PCIe_address_space addr_DRAM_MEM_2(MEM,
									   DRAM_MEM_START_ADDRESS_OVER_4G_HIGH, DRAM_MEM_START_ADDRESS_OVER_4G_LOW,
									   DRAM_MEM_END_ADDRESS_OVER_4G_HIGH, DRAM_MEM_END_ADDRESS_OVER_4G_LOW);

	PCIe_address_space addr_DMI_MEM_2(MEM,
									  DMI_MEM_START_ADDRESS_OVER_4G_HIGH, DMI_MEM_START_ADDRESS_OVER_4G_LOW,
									  DMI_MEM_END_ADDRESS_OVER_4G_HIGH, DMI_MEM_END_ADDRESS_OVER_4G_LOW);

	
	PCIe_address_space addr_SATA_1_MEM_1(MEM,
										 0x0, SATA_MEM_START_ADDRESS_UNDER_4G,
										 0x0, SATA_MEM_END_ADDRESS_UNDER_4G);
	PCIe_address_space addr_SATA_1_IO(IO,
									  0x0, SATA_IO_START_ADDRESS,
									  0x0, SATA_IO_END_ADDRESS);
	PCIe_address_space addr_SATA_1_CONF(CONF,
										0x0, SATA_CONF_START_ADDRESS,
										0x0, SATA_CONF_END_ADDRESS);
	
	PCIe_address_space addr_SATA_1_MEM_2(MEM,
										 SATA_MEM_START_ADDRESS_OVER_4G_HIGH, SATA_MEM_START_ADDRESS_OVER_4G_LOW,
										 SATA_MEM_END_ADDRESS_OVER_4G_HIGH, SATA_MEM_END_ADDRESS_OVER_4G_LOW);

	if (SYSTEM_TYPE == 1)
		CPU_1 = new CPU("CPU", SOUTH_MAIN_DMA_PRD_START_ADDRESS, SOUTH_MAIN_DMA_PRD_START_ADDRESS, SOUTH_DMA_COMMAND_REG_START_ADDRESS, SYSTEM_TYPE, EXPERIMENT_TYPE, DMA_SIZE, DMA_COMMAND);
	else if (SYSTEM_TYPE == 2)
		CPU_1 = new CPU("CPU", NORTH_MAIN_DMA_PRD_START_ADDRESS, NORTH_MAIN_DMA_PRD_START_ADDRESS, NORTH_DMA_COMMAND_REG_START_ADDRESS, SYSTEM_TYPE, EXPERIMENT_TYPE, DMA_SIZE, DMA_COMMAND);
	else if (SYSTEM_TYPE == 3)
		CPU_1 = new CPU("CPU", NORTH_MAIN_DMA_PRD_START_ADDRESS, NORTH_SSD_DMA_PRD_START_ADDRESS, NORTH_DMA_COMMAND_REG_START_ADDRESS, SYSTEM_TYPE, EXPERIMENT_TYPE, DMA_SIZE, DMA_COMMAND);
	else
		CPU_1 = new CPU("CPU", SOUTH_MAIN_DMA_PRD_START_ADDRESS, SOUTH_SSD_DMA_PRD_START_ADDRESS, SOUTH_DMA_COMMAND_REG_START_ADDRESS, SYSTEM_TYPE, EXPERIMENT_TYPE, DMA_SIZE, DMA_COMMAND);
	Root_Complex = new PCIe_Root_Complex("PCIe_Root_Complex", HOST_DRAM_CONTROLLER_ID, NORTH_DMA_ID,
										 NORTH_MAIN_DMA_PRD_START_ADDRESS, NORTH_DMA_COMMAND_REG_START_ADDRESS, NORTH_DMA_CHECK_REG_START_ADDRESS,
										 addr_DRAM_MEM_1, addr_DRAM_IO, addr_DRAM_CONF,
										 addr_DMI_MEM_1, addr_DMI_IO, addr_DMI_CONF,
										 addr_DRAM_MEM_2, addr_DMI_MEM_2,
										 SYSTEM_TYPE, 1, 2, 11, 10); // 128MB
	Switch = new PCIe_Switch("PCIe_Switch", SWITCH_ID, addr_SATA_1_MEM_1, addr_SATA_1_IO, addr_SATA_1_CONF, addr_SATA_1_MEM_2);
	SATA_Controller_1 = new PCIe_SATA_Controller("PCIe_SATA_Controller", SATA_CONTROLLER_1_ID, SOUTH_MAIN_DMA_PRD_START_ADDRESS, SOUTH_DMA_COMMAND_REG_START_ADDRESS, SOUTH_DMA_CHECK_REG_START_ADDRESS,
												 addr_SATA_1_MEM_1, addr_SATA_1_IO, addr_SATA_1_CONF, addr_SATA_1_MEM_2,
												 SYSTEM_TYPE, 1, 2, 11, 10); // 128MB
	DDR_SDRAM_1 = new SDRAM_DDR_device("DDR_SDRAM1");	// 128MB
	DPDRAM_1 = new SDRAM_DDR_DP_device("DPDRAM1");		// 128MB
	DDR_SSD_1 = new DDR_SSD("DDR_SSD", NORTH_SSD_DMA_PRD_START_ADDRESS, NORTH_DMA_COMMAND_REG_START_ADDRESS-(DRAM_MEM_END_ADDRESS_UNDER_4G/2+1), NORTH_DMA_CHECK_REG_START_ADDRESS-(DRAM_MEM_END_ADDRESS_UNDER_4G/2+1),
							SYSTEM_TYPE, 1, 2, 11, 10); // 128MB
	DDR_SSD_NAND_1 = new NAND_device("DDR_SSD_NAND1");				// 128MB
	DDR_SSD_NAND_2 = new NAND_device("DDR_SSD_NAND2");				// 128MB
	SATA_SSD_NAND_1 = new NAND_device("SATA_SSD_NAND1");				// 128MB
	SATA_SSD_NAND_2 = new NAND_device("SATA_SSD_NAND2");				// 128MB
	SATA_SSD_1 = new SATA_SSD("SATA_SSD", SOUTH_SSD_DMA_PRD_START_ADDRESS, SOUTH_DMA_COMMAND_REG_START_ADDRESS, SOUTH_DMA_CHECK_REG_START_ADDRESS,
							SYSTEM_TYPE, 1, 2, 11, 10);	// 128MB
//	NAND_Flash = new NAND_flash("Nand_Flash");		// 128MB

	CPU_1->CLK(CPU_CLK);
	Root_Complex->CPU_CLK(CPU_CLK);
	Root_Complex->DRAM_CLK(DRAM_CLK);
	Root_Complex->DMI_CLK(PCIe_CLK);
	Switch->CLK(PCIe_CLK);
	SATA_Controller_1->PCIe_CLK(PCIe_CLK);
	SATA_Controller_1->SATA_CLK(SATA_CLK);
	DDR_SDRAM_1->CLK(DRAM_CLK);
	DPDRAM_1->CLK(DRAM_CLK);
	DDR_SSD_1->DRAM_CLK(DRAM_CLK);
	DDR_SSD_1->FLASH_CLK(FLASH_CLK);
	SATA_SSD_1->SATA_CLK(SATA_CLK);
	SATA_SSD_1->DRAM_CLK(DRAM_CLK);
	SATA_SSD_1->FLASH_CLK(FLASH_CLK);
	DDR_SSD_NAND_1->CLK(FLASH_CLK);
	DDR_SSD_NAND_2->CLK(FLASH_CLK);
	SATA_SSD_NAND_1->CLK(FLASH_CLK);
	SATA_SSD_NAND_2->CLK(FLASH_CLK);
//	NAND_Flash->CLK(FLASH_CLK);

	CPU_1->RSTn(RSTn);
	Root_Complex->RSTn(RSTn);
	Switch->RSTn(RSTn);
	SATA_Controller_1->RSTn(RSTn);
	DDR_SDRAM_1->RSTn(RSTn);
	DPDRAM_1->RSTn(RSTn);
	DDR_SSD_1->RSTn(RSTn);
	DDR_SSD_NAND_1->RSTn(RSTn);
	DDR_SSD_NAND_2->RSTn(RSTn);
	SATA_SSD_1->RSTn(RSTn);
	SATA_SSD_NAND_1->RSTn(RSTn);
	SATA_SSD_NAND_2->RSTn(RSTn);

	CPU_1->system_port(*Root_Complex);
	Root_Complex->DMI_port(*Switch);
	Root_Complex->DDR_SDRAM_port(*DDR_SDRAM_1);
	Root_Complex->DPDRAM_port(*DPDRAM_1);
	Root_Complex->SSD_port(*DDR_SSD_1);
	Switch->DMI_port(*Root_Complex);
	Switch->SATA_port(*SATA_Controller_1);
	SATA_Controller_1->SATA_port(*Switch);
	DDR_SSD_1->NAND_port_1(*DDR_SSD_NAND_1);
	DDR_SSD_1->NAND_port_2(*DDR_SSD_NAND_2);
	DDR_SSD_1->DRAM_port(*DPDRAM_1);
	SATA_SSD_1->NAND_port_1(*SATA_SSD_NAND_1);
	SATA_SSD_1->NAND_port_2(*SATA_SSD_NAND_2);
	SATA_SSD_1->DRAM_port(*DPDRAM_1);

	SATA_Controller_1->HRx_Dword(HRx_Dword);
	SATA_Controller_1->HTx_Dword(HTx_Dword);
	SATA_SSD_1->HRx_Dword(HRx_Dword);
	SATA_SSD_1->HTx_Dword(HTx_Dword);
/*
	SATA_SSD_1->DATA_IO(DATA_IO);
	SATA_SSD_1->REb(REb);
	SATA_SSD_1->WEb(WEb);
	SATA_SSD_1->R_nB(R_nB);

	NAND_Flash->DATA_IO(DATA_IO);
	NAND_Flash->REb(REb);
	NAND_Flash->WEb(WEb);
	NAND_Flash->R_nB(R_nB);
*/
	sc_start(RUN_TIME, SC_US);
 
	cout << "**** Simulation End wth No Exception. ****" << endl;

	return 0;
}
